package P3;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;

import java.util.Random;

import P3.ByteOrder;

import NIOCommunication.NIOProcessor;
import NIOCommunication.NIOSocketContext;





public class FileGathererContext extends NIOSocketContext {
	
	private CrawlResult crawler;	
	
	
	public FileGathererContext(NIOProcessor processor, InetSocketAddress address, CrawlResult crawler) {
		super(processor, address);
		GetFiles();
		this.crawler = crawler;
	}

	public FileGathererContext(NIOProcessor processor, CrawlResult crawler)
			throws UnknownHostException {
		super(processor);
		GetFiles();
		this.crawler = crawler;
	}

	String partial = null;
	String Test = null;
	int i = 0;
	int j = 0;

	@Override
	public void OnReadData(byte[] data) {
		if (mSocketChannel.isConnected()) {

			if (partial == null)
				partial = new String(data);
			else
				partial = partial + new String(data);

		}

	}
	@Override
	public void Close()
	{
		try
		{
			if(mSocketChannel != null)
			{
				mSocketChannel.close();
				mSocketChannel = null;
				System.out.println("Closed Socket");
			}
			
			if(mReadBuffer != null)
			{
				mReadBuffer = null;
			}
			
			if(mCurrentWriteBuffer != null)
			{
				mCurrentWriteBuffer = null;
			}
                        mClosed = true;
                        OnChannelClosed(this);
                        parseFilesList(partial.getBytes());

		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
		
	}
	
	
	public void parseFilesList(byte[] flist) {
		
		System.out.println("Parsefile executed");
	   	String entireMessage = new String(flist);
        int beginIndex=findEndOfHeader(flist);
        if (beginIndex<1){
            return;
        }
        String Header=new String(subBuffer(flist,0,beginIndex));
        int temp1=Header.indexOf("Server:");
        int temp2=Header.indexOf('\n',temp1);
        Header=Header.substring(temp1+8,temp2);
        Header.trim();
        temp1=Header.indexOf('/');
        if (temp1==-1) 
            temp1=Header.indexOf(' ');
        
        Header=Header.substring(0,temp1);
//        cResultVector.setAgent(Header);
        flist=subBuffer(flist,beginIndex,flist.length);
        int length;
        String msg=new String();
        
        while (flist.length>0){
            flist=subBuffer(flist,19,flist.length);
            msg=new String(flist);
            length=ByteOrder.leb2int(subBuffer(flist,0,4),0);

            byte[] qhit=subBuffer(flist,4,length);
            processQueryHitVector(qhit);
            flist=subBuffer(flist,length+4,flist.length);
            if (flist==null)
                break;            
        }
	}

	protected byte[] subBuffer(byte[] buffer, int beginIndex, int endIndex) {

		if (beginIndex > buffer.length) {
			return null;

		}
		if (endIndex > buffer.length) {
			endIndex = buffer.length;
		}
		int bLen = endIndex - beginIndex;
		byte[] result = new byte[bLen];

		System.arraycopy(buffer, beginIndex, result, 0, bLen);

		return result;
	}

	private void processQueryHitVector(byte[] qhit) {
		int beginIndex;
		int endIndex;
		int numOfFiles = qhit[0];
		String sentList = new String();
		String filesList = new String();
		String msg = new String();

		qhit = subBuffer(qhit, 11, qhit.length);
		msg = new String(qhit);

		byte[] fname = new byte[512];
		int num = 0;
		
		boolean initialized = false;
		while (qhit.length > 0 && num < numOfFiles) {
			
			
			ByteBuffer buf = ByteBuffer.wrap(qhit);

			buf.position(4);

		    byte[] bytes = new byte[buf.remaining()];

		    qhit = subBuffer(qhit, 8, qhit.length);

			
			endIndex = bufferIndexOf(qhit, '\0');
			fname = subBuffer(qhit, 0, endIndex);
			qhit = subBuffer(qhit, endIndex + 1, qhit.length);
			msg = new String(fname);
			filesList += msg;
			filesList += '\0';
			String ext = msg.substring(msg.length()-3, msg.length());
			System.out.println(msg + ":" + buf.getInt(3) + " extension:" + ext);
			endIndex = bufferIndexOf(qhit, '\0');
			qhit = subBuffer(qhit, endIndex + 1, qhit.length);
			
			if(initialized == false){
				crawler.InitializeCrawResult(numOfFiles, buf.getInt(3), ext);
				initialized = true;
			}else{
				int temp = buf.getInt(3);
				crawler.setFileExtensions(ext);
				crawler.setMinMaxFileLength(temp);	
				crawler.setAvgFileLength(temp);
			}
			
			num++;
			if (qhit == null)
				break;
		}

	}

	public static int leb2int(byte[] x, int offset) {
		// Must mask value after left-shifting, since case from byte
		// to int copies most significant bit to the left!
		int x0 = x[offset] & 0x000000FF;
		int x1 = (x[offset + 1] << 8) & 0x0000FF00;
		int x2 = (x[offset + 2] << 16) & 0x00FF0000;
		int x3 = (x[offset + 3] << 24);
		return x3 | x2 | x1 | x0;
	}

	protected int bufferIndexOf(byte[] buffer, char c) {

		for (int i = 0; i < buffer.length; i++) {
			if (buffer[i] == c) {
				return i;
			}
		}
		return -1;
	}

	protected int findEndOfHeader(byte[] packet) {

		for (int i = 0; i <= packet.length - 4; i++) {
			if (packet[i] == '\r' && packet[i + 1] == '\n'
					&& packet[i + 2] == '\r' && packet[i + 3] == '\n') {
				return i + 4;
			}
		}
		return -1;
	}

	public void GetFiles() {
		StringBuffer request = new StringBuffer();
		String localAddress = mSocketChannel.socket().getLocalAddress()
				.getHostAddress();

		System.out.println(mSocketChannel.isConnected());
		request.append("GET / HTTP/1.1\r\n" + "Host: "
				+ /* "128.189.183.77" */localAddress + "\r\n"
				+ "User-Agent: UBCECE/0.1\r\n"
				+ "Accept: text/html, application/x-gnutella-packets\r\n"
				+ "Connection: close\r\n" + "\r\n");

		byte[] bytes = request.toString().getBytes();
		WriteData(bytes);
		System.out.println("Sent:\n" + request.toString());
	}

}
